/* proxydroid - Global / Individual Proxy App for Android
 * Copyright (C) 2011 Max Lv <max.c.lv@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * 
 *                            ___====-_  _-====___
 *                      _--^^^#####//      \\#####^^^--_
 *                   _-^##########// (    ) \\##########^-_
 *                  -############//  |\^^/|  \\############-
 *                _/############//   (@::@)   \\############\_
 *               /#############((     \\//     ))#############\
 *              -###############\\    (oo)    //###############-
 *             -#################\\  / VV \  //#################-
 *            -###################\\/      \//###################-
 *           _#/|##########/\######(   /\   )######/\##########|\#_
 *           |/ |#/\#/\#/\/  \#/\##\  |  |  /##/\#/  \/\#/\#/\#| \|
 *           `  |/  V  V  `   V  \#\| |  | |/#/  V   '  V  V  \|  '
 *              `   `  `      `   / | |  | | \   '      '  '   '
 *                               (  | |  | |  )
 *                              __\ | |  | | /__
 *                             (vvv(VVV)(VVV)vvv)
 *
 *                              HERE BE DRAGONS
 *
 */

package proxydroid.org.proxydroid;
import com.example.com.utils.ShellUtils;
import java.io.FileOutputStream;
import proxydroid.org.proxydroid.utils.Utils;

public class ProxyDroidService {
    public static final String BASE = "/data/local/tmp/proxy_test/";
    private static final int MSG_CONNECT_START = 0;
    private static final int MSG_CONNECT_FINISH = 1;
    private static final int MSG_CONNECT_SUCCESS = 2;
    private static final int MSG_CONNECT_FAIL = 3;
    private static final int MSG_CONNECT_PAC_ERROR = 4;
    private static final int MSG_CONNECT_RESOLVE_ERROR = 5;

    final static String CMD_IPTABLES_RETURN = "iptables -t nat -A OUTPUT -p tcp -d 0.0.0.0 -j RETURN\n";
    final static String CMD_IPTABLES_REDIRECT_ADD_HTTP = "iptables -t nat -A OUTPUT -p tcp --dport 80 -j REDIRECT --to 8123\n"
            + "iptables -t nat -A OUTPUT -p tcp --dport 443 -j REDIRECT --to 8124\n"
            + "iptables -t nat -A OUTPUT -p tcp --dport 5228 -j REDIRECT --to 8124\n";
    final static String CMD_IPTABLES_DNAT_ADD_HTTP = "iptables -t nat -A OUTPUT -p tcp --dport 80 -j DNAT --to-destination 127.0.0.1:8123\n"
            + "iptables -t nat -A OUTPUT -p tcp --dport 443 -j DNAT --to-destination 127.0.0.1:8124\n"
            + "iptables -t nat -A OUTPUT -p tcp --dport 5228 -j DNAT --to-destination 127.0.0.1:8124\n";
    final static String CMD_IPTABLES_REDIRECT_ADD_HTTP_TUNNEL = "iptables -t nat -A OUTPUT -p tcp --dport 80 -j REDIRECT --to 8123\n"
            + "iptables -t nat -A OUTPUT -p tcp --dport 443 -j REDIRECT --to 8123\n"
            + "iptables -t nat -A OUTPUT -p tcp --dport 5228 -j REDIRECT --to 8123\n";
    final static String CMD_IPTABLES_DNAT_ADD_HTTP_TUNNEL = "iptables -t nat -A OUTPUT -p tcp --dport 80 -j DNAT --to-destination 127.0.0.1:8123\n"
            + "iptables -t nat -A OUTPUT -p tcp --dport 443 -j DNAT --to-destination 127.0.0.1:8123\n"
            + "iptables -t nat -A OUTPUT -p tcp --dport 5228 -j DNAT --to-destination 127.0.0.1:8123\n";
    final static String CMD_IPTABLES_REDIRECT_ADD_SOCKS = "iptables -t nat -A OUTPUT -p tcp -j REDIRECT --to 8123\n";
    final static String CMD_IPTABLES_DNAT_ADD_SOCKS = "iptables -t nat -A OUTPUT -p tcp -j DNAT --to-destination 127.0.0.1:8123\n";
    private static final String TAG = "ProxyDroidService";
    private String host;
    private int port;
    private String bypassAddrs = "";
    private String user;
    private String password;
    private String domain;
    private String proxyType = "http";
    private String auth = "false";
    private boolean isAuth = false;                             //是否认证用户名密码
    private boolean isNTLM = false;                             //NTLM认证
    private boolean isPAC = false;                              //PAC
    private boolean hasRedirectSupport = true;                  //是否可以转发，默认为是，目前
    private boolean isAutoSetProxy = false;
    private boolean isBypassApps = false;
    private Profile profile;

    public void setProfile(Profile profile) {
        this.profile = profile;
    }

    public Profile getProfile() {
        return profile;
    }

    //构造函数
    public ProxyDroidService(Profile profile) {
        this.profile = profile;
    }

    /**
     * Internal method to request actual PTY terminal once we've finished
     * authentication. If called before authenticated, it will just fail.
     */
    private void enableProxy() {
        String proxyHost = host;
        int proxyPort = port;
        try {
            if (proxyType.equals("https")) {
                // Configure file for Stunnel
                FileOutputStream fs = new FileOutputStream(BASE + "stunnel.conf");
                String conf = "debug = 0\n" + "client = yes\n" + "pid = " + BASE + "stunnel.pid\n"
                        + "[https]\n" + "sslVersion = all\n" + "accept = 127.0.0.1:8126\n"
                        + "connect = " + host + ":" + port + "\n";
                fs.write(conf.getBytes());
                fs.flush();
                fs.close();

                // Start stunnel here
                Utils.runRootCommand(BASE + "stunnel " + BASE + "stunnel.conf");

                // Reset host / port
                proxyHost = "127.0.0.1";
                proxyPort = 8126;
                proxyType = "http";
            }

            if (proxyType.equals("http") && isAuth && isNTLM) {
                Utils.runRootCommand(BASE + "proxy.sh start http 127.0.0.1 8025 false\n" + BASE
                        + "cntlm -P " + BASE + "cntlm.pid -l 8025 -u " + user
                        + (!domain.equals("") ? "@" + domain : "@local") + " -p " + password + " "
                        + proxyHost + ":" + proxyPort + "\n" + BASE
                        + "tproxy -P /data/data/org.proxydroid/tproxy.pid -s 8125 127.0.0.1 8025\n");
            } else {
                final String u = Utils.preserve(user);
                final String p = Utils.preserve(password);

                ShellUtils.execCommand(BASE + "proxy.sh start" + " " + proxyType + " " + proxyHost
                        + " " + proxyPort + " " + auth + " \"" + u + "\" \"" + p + "\"", true);
            }


            StringBuffer cmd = new StringBuffer();
            cmd.append(CMD_IPTABLES_RETURN.replace("0.0.0.0", host));

            if (bypassAddrs != null && !bypassAddrs.equals("")) {
                String[] addrs = Profile.decodeAddrs(bypassAddrs);
                for (String addr : addrs)
                    cmd.append(CMD_IPTABLES_RETURN.replace("0.0.0.0", addr));
            }

            String redirectCmd = CMD_IPTABLES_REDIRECT_ADD_HTTP;
            String dnatCmd = CMD_IPTABLES_DNAT_ADD_HTTP;

            if (proxyType.equals("socks4") || proxyType.equals("socks5")) {
                redirectCmd = CMD_IPTABLES_REDIRECT_ADD_SOCKS;
                dnatCmd = CMD_IPTABLES_DNAT_ADD_SOCKS;
            } else if (proxyType.equals("http-tunnel")) {
                redirectCmd = CMD_IPTABLES_REDIRECT_ADD_HTTP_TUNNEL;
                dnatCmd = CMD_IPTABLES_DNAT_ADD_HTTP_TUNNEL;
            }

            //如果为全局则proxyedApps，为空。isBypassApps为false
            //如果false，则proxyedApps中的app设置为代理，其他不设置为代理
            //如果true，则proxyedApps中的app不设置代理，其他设置为代理
            //对于此项目来说这两个参数没有意义
            if (isBypassApps) {
                // for host specified apps
//                if (apps == null || apps.length <= 0)
//                    //apps = AppManager.getProxyedApps(this, false);
//
//                for (int i = 0; i < apps.length; i++) {
//                    if (apps[i] != null && apps[i].isProxyed()) {
//                        cmd.append(CMD_IPTABLES_RETURN.replace("-d 0.0.0.0", "").replace("-t nat",
//                                "-t nat -m owner --uid-owner " + apps[i].getUid()));
//                    }
//                }
            }

            if (isAutoSetProxy || isBypassApps) {
                cmd.append(hasRedirectSupport ? redirectCmd : dnatCmd);
            } else {
                // for host specified apps
//                if (apps == null || apps.length <= 0)
//                    //apps = AppManager.getProxyedApps(this, true);
//
//                for (int i = 0; i < apps.length; i++) {
//                    if (apps[i] != null && apps[i].isProxyed()) {
//                        cmd.append((hasRedirectSupport ? redirectCmd : dnatCmd).replace("-t nat",
//                                "-t nat -m owner --uid-owner " + apps[i].getUid()));
//                    }
//                }
            }
            String rules = cmd.toString();
            if (proxyType.equals("http") && isAuth && isNTLM)
                rules = rules.replace("8123", "8125");
            rules = rules.replace("iptables", Utils.getIptables());
            Utils.runRootCommand(rules);

        } catch (Exception e) {
            //Log.e(TAG, "Error setting up port forward during connect", e);
        }

    }

    /**
     * Called when the activity is first created.
     */
    public boolean handleCommand() {
        String cmds = "chmod 777 /data/local/tmp/proxy_test/iptables\n"
                + "chmod 777 /data/local/tmp/proxy_test/redsocks\n"
                + "chmod 777 /data/local/tmp/proxy_test/proxy.sh\n"
                + "chmod 777 /data/local/tmp/proxy_test/cntlm\n"
                + "chmod 777 /data/local/tmp/proxy_test/tproxy\n"
                + "chmod 777 /data/local/tmp/proxy_test/stunnel\n";
        ShellUtils.execCommand(cmds, true);
        enableProxy();
        return true;
    }

    private void stopProxy() {
        final StringBuilder sb = new StringBuilder();
        sb.append(Utils.getIptables() + " -t nat -F OUTPUT\n");
        if (proxyType.equals("https")) {
            sb.append("kill -9 `cat /data/local/tmp/proxy_test/stunnel.pid`\n");
        }
        if (isAuth && isNTLM) {
            sb.append("kill -9 `cat /data/local/tmp/proxy_test/cntlm.pid`\n"
                    + "kill -9 `cat /data/local/tmp/proxy_test/tproxy.pid`\n");
        }
        sb.append(BASE + "proxy.sh stop\n");
    }

    //入口
    public void startProxy() {
        //Log.d(TAG, "Service Start");
        host = this.profile.getHost();
        bypassAddrs = this.profile.getBypassAddrs();
        proxyType = this.profile.getProxyType();
        port = this.profile.getPort();
        isAutoSetProxy = this.profile.isAutoSetProxy();
        isBypassApps = this.profile.isBypassApps();
        isAuth = this.profile.isAuth();
        isNTLM = this.profile.isNTLM();
        isPAC = this.profile.isPAC();
        if (isAuth) {
            auth = "true";
            user = this.profile.getUser();
            password = this.profile.getPassword();
        } else {
            auth = "false";
            user = "";
            password = "";
        }
        if (isNTLM)
            domain = this.profile.getDomain();
        else
            domain = "";
        hasRedirectSupport = Utils.getHasRedirectSupport();          //是否可以设置转发，有些手机不行
        handleCommand();
    }
    private String getUid(String packageNmae) {
        String ret = "";
        String cmds = "chmod 777 /data/system/packages.list";
        ShellUtils.execCommand(cmds, true);
        cmds = "cat /data/system/packages.list |grep " + packageNmae;
        ShellUtils.CommandResult cret = ShellUtils.execCommand(cmds, true);
        String[] cretArray = cret.successMsg.split(" ");
        ret = cretArray[1];
        return ret;
    }
}
